home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1997 January
/
Macworld (1997-01).dmg
/
Games World
/
Shareware Games
/
Arcade
/
Mike's Breakout
/
Game.u
next >
Wrap
Text File
|
1996-10-11
|
32KB
|
919 lines
{send all comments/gripes/etc to ani@atlas.nmsu.edu}
{feel free to use this code for whatever you'd like. i'd be grateful i helped make someone's day just a bit brighter}
unit Game;
interface
uses
Notification, AppleTalk, PPCToolbox, Processes, EPPC, Events, AppleEvents, MTGW, TypeConst, Graphics, MTSound;
{why all the toolbox stuff? well, i made a function that (supposedly) kills other apps and the finder, and it wants this stuff}
procedure InitOb (var WhichOb: ListGameObject; OID: integer; OInterpretID: integer; OFrame: integer; OCurrentPlace: Rect; OLastPlace: Rect; ONext: ListGameObject; OPrevious: ListGameObject; OA: integer; OB: integer; OC: integer; OD: integer; OE: integer; OVF: integer; OG: integer; OH: integer);
procedure InitGame;
procedure DisposeAll (FirstNonMovingObject, FirstMovingObject: ListGameObject);
procedure InitLevel (WhichLevel: integer; var FirstNonMovingObject: ListGameObject; var FirstMovingObject: ListGameObject);
procedure GameLoop (FirstNonMovingObject, FirstMovingObject: ListGameObject);
procedure DoCurrentKey;
procedure Interpret (WhichOb: ListGameObject);
procedure CollisionBallInterpret (var WhichOb, HitOb: ListGameObject);
procedure CollisionExplosionInterpret (var WhichOb, HitOb: ListGameObject);
procedure CollisionInterpret (var WhichOb, HitOb: ListGameObject);
procedure PaddleInterpret (WhichOb: ListGameObject);
procedure MissileInterpret (WhichOb: ListGameObject);
procedure BallInterpret (WhichOb: ListGameObject);
procedure ExplosionInterpret (WhichOb: ListGameObject);
procedure PieceInterpret (WhichOb: ListGameObject);
procedure FIREYDEATH (WhichOb: ListGameObject; XOffset, YOffset, Grow: integer);
procedure YOUSUCK (WhichOb: ListGameObject);
procedure SplitParts (WhichOb: ListGameObject);
procedure BrickEnd (WhichBrick, WhichOb: ListGameObject);
procedure MissileLaunch (var WhichOb: ListGameObject);
procedure PaddleAndBall (var FirstObject: ListGameObject);
function Collision (FirstRect: Rect; SecondRect: Rect): Rect;
function NormalCollision (var CurrOb: ListGameObject): Boolean;
procedure BrickRow (var StartOb: ListGameObject; XStart: integer; YStart: integer; NumBricks: integer);
procedure InitNonMovingGrid;
procedure RemoveFromNonMovingGrid (CurrOb: ListGameObject);
procedure AddToNonMovingGrid (CurrOb: ListGameObject);
procedure UpdateNonMovingGrid (CurrOb: ListGameObject);
procedure KillEveryBody;
var {explained when they are used}
OtherBool, DontSuck, PaddleDeath, BallDeath, ShiftKeyIsDown, GotEvent, Done: Boolean;
CurrentEvent: EventRecord;
CurrentKey: char;
Temp: integer;
TempOb: ListGameObject;
FirstPlace, TempPlace: Rect;
Topscore: file of longint;
implementation
procedure KillEveryBody; {ok i haven't looked over this function 100%, as it is only a conversion}
{of a C program i found somewhere on apple's site to pascal, and I may have converted improperly. the}
{function SHOULD kill all other processes, but most of the time when i try it, it will do that, then crash}
{my machine sometime later. have a look-see yourself}
var
finderPSN, myProc, processSN: ProcessSerialNumber;
inforec: ProcessInfoRec;
processName: Str31;
procSpec: FSSpec;
fredErr, myErr, otherError: OsErr;
replyEvent, theEvent: AppleEvent;
theAddress: AEDesc;
ourFlag, notFinder: Boolean;
finderFound: Boolean;
begin
fredErr := GetCurrentProcess(myProc);
processSN.lowLongOfPSN := kNoProcess;
myerr := noErr;
finderFound := FALSE;
processSN.highLongOfPSN := kNoProcess;
finderPSN.lowLongOfPSN := 0;
finderPSN.highLongOfPSN := 0;
repeat
myErr := GetNextProcess(processSN);
notFinder := true;
fredErr := SameProcess(myProc, processSN, ourFlag);
infoRec.processInfoLength := sizeof(ProcessInfoRec);
infoRec.processName := @processName;
infoRec.processAppSpec := @procSpec;
fredErr := GetProcessInformation(processSN, infoRec);
if ((not ourFlag) and (not finderFound)) then
begin
if (infoRec.processSignature = 'MACS') and (infoRec.processType = longint('FNDR')) then
begin
finderPSN := processSN;
notFinder := false;
finderFound := true;
end
else
notFinder := true;
end;
if ((myErr = noerr) and ((not ourFlag) and (notFinder))) then
otherError := AECreateDesc(typeProcessSerialNumber, Ptr(@processSN), sizeof(processSN), theAddress);
if (otherError = noerr) then
otherError := AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, theAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
if (otherError = noerr) then
fredErr := AEDisposeDesc(theAddress);
if (otherError = noerr) then
fredErr := AESend(theEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil);
fredErr := AEDisposeDesc(theEvent);
until (myErr <> noerr);
if ((finderPSN.lowLongOfPSN <> 0) or (finderPSN.highLongOfPSN <> 0)) then
otherError := AECreateDesc(typeProcessSerialNumber, Ptr(@finderPSN), sizeof(processSN), theAddress);
if (otherError = noerr) then
otherError := AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, theAddress, kAutoGenerateReturnID, kAnyTransactionID, theEvent);
if (otherError = noerr) then
fredErr := AEDisposeDesc(theAddress);
if (otherError = noerr) then
fredErr := AESend(theEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil);
fredErr := AEDisposeDesc(theEvent);
end; {fun stuff...}
procedure CollisionBallInterpret;
begin
case HitOb^.InterpretID of
BRICK:
begin
{BrickEnd(HitOb, WhichOb);}
{uncomment previous line to have brick do a shrinking animation (and slow your machine, ugh)}
with WhichOb^ do
begin
F := C;
if C > 0 then
C := C - 1;
end;
HitOb^.DoDispose := TRUE;
PlaySound(129);
end;
BRICKII:
begin
if WhichOb^.C <> 0 then
begin
HitOb^.DoDispose := TRUE;
PlaySound(129);
end
else
PlaySound(132);
WhichOb^.C := 0;
end;
end;
end; {this function checks what to do when the ball collides with a certain object}
procedure CollisionExplosionInterpret;
begin
case HitOb^.ID of
BRICK:
begin
{BrickEnd(HitOb, WhichOb);}
HitOb^.DoDispose := TRUE;
end;
end;
end; {this checks what to do when an explosion hits an object}
procedure CollisionInterpret;
begin
case WhichOb^.ID of
BALL:
begin
CollisionBallInterpret(WhichOb, HitOb);
end;
EXPLOSION:
CollisionExplosionInterpret(WhichOb, HitOb);
otherwise
;
end;
end; {this goes to the correct interpretation for collisions, depending on the object;}
{function pointers would probably be better}
function NormalCollision;
var
WhereX, WhereY, k: integer;
ReturnValue: Boolean;
begin
ReturnValue := FALSE;
for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
if (WhereX >= 0) and (WhereY >= 0) and (WhereX < MAXGRIDX) and (WhereY < MAXGRIDY) then
for k := 1 to 5 do {check each grid object in the part of the grid that the current object covers}
begin
if NonMovingGrid[WhereX, WhereY, k] <> nil then {we got something? if so call collisioninterpret}
begin
if SectRect(NonMovingGrid[WhereX, WhereY, k]^.CurrentPlace, CurrOb^.CurrentPlace, TempPlace) then
begin
CollisionInterpret(CurrOb, NonMovingGrid[WhereX, WhereY, k]);
ReturnValue := TRUE;
end;
end;
end;
NormalCollision := ReturnValue;
end; {grid type of collision}
function Collision;
var
ReturnVariable: Rect;
begin
if not SectRect(FirstRect, SecondRect, ReturnVariable) then
ReturnVariable.top := -1
else
PlaySound(129);
Collision := ReturnVariable;
end; {check if too objects collided (and play fun sound) }
procedure InitOb; {each object property is described here!}
begin
with WhichOb^ do
begin
ID := OID; {This is the drawing ID (very much wants to be a function pointer)}
InterpretId := OInterpretID; {This is the interpret, or heart_beat id, the func called every iteration ("")}
Frame := OFrame; {This is the frame counter}
CurrentPlace := OCurrentPlace; {A rect for the current location}
LastPlace := OLastPlace; {A rect for the last location}
Next := ONext; {the next object in the linked list}
Previous := OPrevious; {the previous object in the linked list}
A := OA; {A-D misc values}
B := OB;
C := OC;
D := OD;
DoDispose := FALSE; {this important variable decides if the object is to be removed from memory}
{at the end of a turn of the main loop}
end;
end;
{this is very simply a macro to put all of an object's properties in one line}
procedure YOUSUCK;
var
WhichRect: Rect;
CurrOb: ListGameObject;
begin
CurrOb := WhichOb;
while CurrOb^.previous <> nil do
CurrOb := CurrOb^.previous;
new(CurrOb^.previous);
PlaySound(134);
with WhichOb^ do
CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left, WhichOb^.CurrentPlace.top - 20, CIcons[900]^^.IconPmap.Bounds.right, CIcons[900]^^.IconPmap.Bounds.bottom);
InitOb(CurrOb^.previous, PADDLEEXP, PADDLEEXP, 899, WhichRect, WhichRect, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
end; {game over function, creates and explosion at the very beginning of the linked list}
{we also have michael to thank for the 'colourful' function name}
procedure SplitParts;
var
WhichRect: Rect;
StartOb, CurrOb: ListGameObject;
begin
StartOb := WhichOb;
CurrOb := WhichOb^.Next;
WhichOb^.Next := nil;
new(WhichOb^.Next); {create a new object AFTER the explosion (or the caller of this function)}
with WhichOb^.Next^ do
CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left, WhichOb^.CurrentPlace.top + 10, CIcons[1000]^^.IconPmap.Bounds.right, CIcons[1000]^^.IconPmap.Bounds.bottom);
InitOb(WhichOb^.Next, PADDLEPIECE, PADDLEPIECE, 1000, WhichRect, WhichRect, CurrOb, WhichOb, -15, -2, 0, 0, 0, 0, 0, 0);
CurrOb^.Previous := WhichOb^.Next;
WhichOb := CurrOb;
CurrOb := WhichOb^.Next;
WhichOb^.Next := nil;
new(WhichOb^.Next); {create another piece after the previous piece}
with WhichOb^.Next^ do
with WhichOb^ do
CoordAndSize(WhichRect, StartOb^.CurrentPlace.left + 23, StartOb^.CurrentPlace.top + 10, CIcons[1050]^^.IconPmap.Bounds.right, CIcons[1050]^^.IconPmap.Bounds.bottom);
InitOb(WhichOb^.Next, PADDLEPIECE, PADDLEPIECE, 1050, WhichRect, WhichRect, CurrOb, WhichOb, 15, -2, 0, 0, 0, 0, 0, 0);
if CurrOb <> nil then
CurrOb^.Previous := WhichOb^.Next;
end; {this function creates two ends of the paddle}
procedure FIREYDEATH;
var
WhichRect: Rect;
CurrOb: ListGameObject;
begin
CurrOb := WhichOb;
while CurrOb^.previous <> nil do
CurrOb := CurrOb^.previous;
PlaySound(133);
new(CurrOb^.previous); {create an explosion at the very beginning of the list}
with WhichOb^ do
CoordAndSize(WhichRect, XOffset + ((WhichOb^.CurrentPlace.left + WhichOb^.CurrentPlace.right) div 2) - ((CIcons[400]^^.IconPmap.Bounds.right) div 2) - 10, YOffset + ((WhichOb^.CurrentPlace.top + WhichOb^.CurrentPlace.bottom) div 2) - ((CIcons[400]^^.IconPmap.Bounds.bottom) div 2), CIcons[400]^^.IconPmap.Bounds.right, CIcons[400]^^.IconPmap.Bounds.bottom);
{^ this long call here just centers the explosion where the thing blew up}
InsetRect(WhichRect, -Grow, -Grow);
InitOb(CurrOb^.previous, EXPLOSION, EXPLOSION, 399, WhichRect, WhichRect, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
with CurrOb^.previous^.CurrentPlace do
begin
right := right + 20;
bottom := bottom + 10;
end; {make it a bit bigger for the flames to fit}
if NormalCollision(CurrOb^.previous) then
; {check if we hit anything with the explosion}
with CurrOb^.previous^ do
begin
LastPlace := CurrentPlace;
CurrentPlace := WhichRect;
InsetRect(LastPlace, -Grow, -Grow);
end;
end; {another 'mike' function name, this creates an all purpose explosion}
procedure BrickEnd;
var
CurrOb: ListGameObject;
begin
CurrOb := WhichOb;
while CurrOb^.previous <> nil do
CurrOb := CurrOb^.previous;
new(CurrOb^.previous); {very beginning of list again}
InitOb(CurrOb^.previous, DEADBRICK, DEADBRICK, 1100, WhichBrick^.CurrentPlace, WhichBrick^.CurrentPlace, CurrOb, nil, 0, 0, 0, 0, 0, 0, 0, 0);
end; {this creates a new object for a shrinking brick}
procedure MissileLaunch;
var
WhichRect: Rect;
NewOb, CurrOb: ListGameObject;
begin
CurrOb := WhichOb^.previous;
WhichOb^.previous := nil;
PlaySound(131);
new(WhichOb^.previous); {create it before the current object}
NewOb := WhichOb^.previous;
if CurrOb <> nil then
CurrOb^.next := NewOb;
CoordAndSize(WhichRect, WhichOb^.CurrentPlace.left + 26, WhichOb^.CurrentPlace.top - 7, CIcons[600]^^.IconPmap.Bounds.right, CIcons[600]^^.IconPmap.Bounds.bottom);
InitOb(NewOb, MISSILE, MISSILE, 350, WhichRect, WhichRect, WhichOb, CurrOb, 0, 0, 0, 0, 0, 0, 0, 0);
end; {just create a missle}
procedure ExplosionInterpret;
begin
with WhichOb^ do
begin
end;
end; {explosion doesn't do anything but look cool after it's initial creation}
procedure BallInterpret;
begin
TempBool := FALSE;
OtherBool := FALSE; {these are used for collisions}
with WhichOb^ do
begin
F := 0;
FirstPlace := CurrentPlace;
if A > 0 then {going right?}
begin
OffsetRect(CurrentPlace, A, 0);
D := 0; {move rect right, init this temp var}
if (WhichOb^.previous^.ID = PADDLE) then
begin
TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
D := integer(TempPlace.top <> -1);
if (D <> 0) then
C := 0; {if we collided with something other then the top, unset the velocity going up or down}
end;
OtherBool := (CurrentPlace.right > RIGHTBOUNDRY);
if OtherBool or (D <> 0) or NormalCollision(WhichOb) then { or collision }
begin
if F = 0 then
A := -1 * A; {if there was a collision then go the other way}
CurrentPlace := FirstPlace;
end;
end
else if A < 0 then {going left looks like going right, so look at it for details}
begin
OffsetRect(CurrentPlace, A, 0);
D := 0;
if (WhichOb^.previous^.ID = PADDLE) then
begin
TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
D := integer(TempPlace.top <> -1);
if (D <> 0) then
C := 0;
end;
OtherBool := (CurrentPlace.left < LEFTBOUNDRY);
if OtherBool or (D <> 0) or NormalCollision(WhichOb) then
begin
if F = 0 then
A := -1 * A;
CurrentPlace := FirstPlace;
end;
end;
F := 0;
if OtherBool then
PlaySound(129);
if B = 1 then {going down?}
begin
OffsetRect(CurrentPlace, 0, 6 * ((C + 4) div 4)); {move depending on the velocity, C}
D := 0;
if (WhichOb^.previous^.ID = PADDLE) then
begin
TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
if TempPlace.top <> -1 then
D := (TempPlace.right + TempPlace.left) div 2 - WhichOb^.previous^.CurrentPlace.left
else
D := 0;
end; {check for collision with paddle}
TempBool := (CurrentPlace.bottom > BOTTOMBOUNDRY); {you lost your ball!}
if TempBool or (D <> 0) or NormalCollision(WhichOb) then {collision with paddle or otherwise}
begin
if F = 0 then
B := -1 * B;
if D <> 0 then
begin
A := ((D - 30) div 7) * 3;
C := 0;
end;
CurrentPlace := FirstPlace;
end;
end
else {going up here, very much like going down, except you don't die if you hit the top}
begin
OffsetRect(CurrentPlace, 0, -6 * ((C + 4) div 4));
D := 0;
if (WhichOb^.previous^.ID = PADDLE) then
begin
TempPlace := Collision(CurrentPlace, WhichOb^.previous^.CurrentPlace);
if TempPlace.top <> -1 then
D := (TempPlace.right + TempPlace.left) div 2 - WhichOb^.previous^.CurrentPlace.left
else
D := 0;
end;
OtherBool := (CurrentPlace.top < TOPBOUNDRY);
if OtherBool or (D <> 0) or NormalCollision(WhichOb) then
begin
if F = 0 then
B := -1 * B;
if D <> 0 then
begin
A := ((D - 30) div 7) * 3;
C := 0;
end;
CurrentPlace := FirstPlace;
end;
end;
if TempBool or BallDeath then {if you lose}
begin
DoDispose := TRUE;
FIREYDEATH(WhichOb, 0, 0, 20);
PaddleDeath := True;
DeathCountdown := 1; {one of the 2 is lost (other two are paddle pieces)}
end;
if OtherBool then
PlaySound(129); {hit a side}
end;
end;
procedure MissileInterpret;
begin
with WhichOb^ do
begin
if (A > -14) then
A := A - 1; {missile goes faster every round}
OffsetRect(CurrentPlace, 0, A);
if (CurrentPlace.top < 0) or NormalCollision(WhichOb) then
begin
DoDispose := TRUE;
FIREYDEATH(WhichOb, 0, 0, 0); {make an explosion where it hit}
{Collide with ceil}
end;
end;
end;
procedure PaddleInterpret;
begin
with WhichOb^ do
begin
A := 0;
if (E = 0) and (CurrentKey = ' ') then {pressed for trampoline?}
begin
E := 15;
end;
if C <> 0 then {missile launching var}
begin
if C = 1 then
begin
frame := frame + 1; {open the doors}
if frame = 203 then
MissileLaunch(WhichOb); {all the way open? do the missile!}
end
else
frame := frame - 1; {close the doors}
if frame = 206 then
C := 2;
if frame = 200 then
C := 0;
end
else
begin
case CurrentKey of {pretty easy stuff, if you pressed right or left go that way}
RIGHTKEY:
begin
A := FLAMELEFT;
if ShiftKeyIsDown then
OffsetRect(CurrentPlace, PADDLESPEED * 3, 0)
else
OffsetRect(CurrentPlace, PADDLESPEED, 0);
Temp := CurrentPlace.right - RIGHTBOUNDRY;
if Temp > 0 then
begin
CurrentPlace.right := CurrentPlace.right - Temp;
CurrentPlace.left := CurrentPlace.left - Temp;
end;
end;
LEFTKEY:
begin
A := FLAMERIGHT;
if ShiftKeyIsDown then
OffsetRect(CurrentPlace, -PADDLESPEED * 3, 0)
else
OffsetRect(CurrentPlace, -PADDLESPEED, 0);
Temp := LEFTBOUNDRY - CurrentPlace.left;
if Temp > 0 then
begin
CurrentPlace.right := CurrentPlace.right + Temp;
CurrentPlace.left := CurrentPlace.left + Temp;
end;
end;
LAUNCHKEY: {begin missile launching}
begin
if Missiles > 0 then
begin
C := 1;
Missiles := Missiles - 1;
end
else
;
end;
otherwise
;
end;
end;
if (E <> 0) then {play with trampoline?}
begin
if E > 10 then
begin
CoordAndSize(ExtraRectA, CurrentPlace.left + 11, CurrentPlace.top - 8, CIcons[650]^^.IconPmap.Bounds.right, CIcons[650]^^.IconPmap.Bounds.bottom);
TempOb := WhichOb^.next;
if TempOb <> nil then
begin
if TempOb^.ID = BALL then {did we smack that ball?}
begin
TempPlace := Collision(ExtraRectA, TempOb^.CurrentPlace);
if TempPlace.top <> -1 then
begin
PlaySound(130);
TempOb^.B := -1;
if (TempOb^.C < 8) then
TempOb^.C := TempOb^.C + 4; {launch ball with tremendous speed!}
end;
end;
end;
end
else
CoordAndSize(ExtraRectA, CurrentPlace.left + 11, CurrentPlace.top + (2 - E), CIcons[650]^^.IconPmap.Bounds.right, CIcons[650]^^.IconPmap.Bounds.bottom);
end;
if PaddleDeath then
begin
DoDispose := TRUE;
PaddleDeath := FALSE;
YOUSUCK(WhichOb); {get ready to lose a life}
end;
end;
end;
procedure PieceInterpret;
begin
with WhichOb^ do
begin
OffSetRect(CurrentPlace, A, B);
B := B + 1;
C := C + 1;
if C = 8 then
C := 0;
end;
end; {just animate it, use C for frame counter, and play with gravity using B}
procedure Interpret;
begin
if WhichOb^.InterpretID <> 0 then
begin
case WhichOb^.InterpretID of
PADDLE:
PaddleInterpret(WhichOb);
MISSILE:
MissileInterpret(WhichOb);
BALL:
BallInterpret(WhichOb);
EXPLOSION:
ExplosionInterpret(WhichOb);
PADDLEPIECE:
PieceInterpret(WhichOb);
PADDLEEXP:
if WhichOb^.frame = 904 then
SplitParts(WhichOb);
otherwise
;
end;
end;
end; {instead of function pointer, pick the one that coresponds to the interpreting id}
procedure DoCurrentKey;
begin
GotEvent := GetOSEvent(everyEvent, CurrentEvent);
CurrentKey := char(0);
ShiftKeyIsDown := FALSE;
if GotEvent then
begin
if (CurrentEvent.What = keyDown) or (CurrentEvent.What = autoKey) then
CurrentKey := char(BitAnd(CurrentEvent.Message, charCodeMask));
if BitAnd(CurrentEvent.Modifiers, shiftKey) <> 0 then
ShiftKeyIsDown := TRUE;
end;
if CurrentKey = QUITKEY then
Done := TRUE;
end; {basic toolbox fun, get the next event that happened and throw it in}
procedure GameLoop; {woo this is the main loop}
var
j, i: integer;
CurrentKey: char;
NextLevel: Boolean;
NextObject, PreviousObject, CurrObject: ListGameObject;
begin
Done := FALSE;
while not Done do
begin
NextLevel := FALSE;
DisposeAll(FirstNonMovingObject, FirstMovingObject);
InitLevel(1, FirstNonMovingObject, FirstMovingObject); {init everything, get rid of stuff every level}
while not Done and not NextLevel do
begin
begin
DoCurrentKey;
if CoolnessCounter > 0 then
CoolnessCounter := CoolnessCounter - 1; {this is a really bad way to give sounds priority(more later)}
while FirstNonMovingObject^.previous <> nil do
FirstNonMovingObject := FirstNonMovingObject^.previous;
while FirstMovingObject^.previous <> nil do
FirstMovingObject := FirstMovingObject^.previous; {go to beginning of list on both lists}
if DeathCountdown = 3 then
begin
Lives := Lives - 1;
if Lives < 1 then
begin
Done := TRUE;
rewrite(TopScore, 'HighScore');
TopScore^ := top;
put(TopScore);
close(TopScore); {you lose a life, high score is written (wow, something mike actually did) }
end
else
PaddleAndBall(FirstMovingObject); {this creates the paddle and the ball}
DeathCountdown := 0;
end;
CurrObject := FirstMovingObject;
FixErasure(FirstMovingObject); {erase everything}
while CurrObject <> nil do
begin
Interpret(CurrObject);
Draw(CurrObject); {for each object, draw and interpret}
if CurrObject^.DoDispose then
begin
NextObject := CurrObject^.next;
PreviousObject := CurrObject^.previous;
if PreviousObject <> nil then
PreviousObject^.next := NextObject;
if NextObject <> nil then
NextObject^.Previous := PreviousObject;
if CurrObject = FirstMovingObject then
FirstMovingObject := NextObject;
dispose(CurrObject);
CurrObject := NextObject; {this just gets rid of one object! complicated work, sort of, as}
end {several checks are done, so it doesn't go before first, after last etc}
else
CurrObject := CurrObject^.Next;
end;
DrawGridSquares;
CurrObject := FirstNonMovingObject;
i := 0;
while CurrObject <> nil do {this loop is for grid, and gives you points when needed}
begin
begin
i := i + 1;
if CurrObject^.DoDispose then
begin
for j := 1 to CurrObject^.A do
begin
score := score + 1;
if (score mod 100) = 0 then
lives := lives + 1;
if (score mod 10) = 0 then
Missiles := Missiles + 1; {every 100 a life, every 10 a missile (sounds fair to me)}
end;
if (score > top) then
begin
top := score;
if not DontSuck then
begin
DontSuck := TRUE;
PlaySound(135);
CoolnessCounter := 35; {this plays the high score sound, then gives a counter for priority}
end;
end;
AddCopyRect(CurrObject^.CurrentPlace);
EraseRect(CurrObject^.CurrentPlace);
RemoveFromNonMovingGrid(CurrObject);
NextObject := CurrObject^.next;
PreviousObject := CurrObject^.previous;
if PreviousObject <> nil then
PreviousObject^.next := NextObject;
if NextObject <> nil then
NextObject^.Previous := PreviousObject;
if CurrObject = FirstMovingObject then
FirstMovingObject := NextObject;
dispose(CurrObject);
CurrObject := NextObject; {this just gets rid of it, as well as removing it from grid}
end
else
CurrObject := CurrObject^.Next;
end
end;
if (i = 1) and (DeathCountdown = 0) then {i is the num of grid objects; which are bricks.. the one left is}
{a dummy object to keep things happy}
begin
PlaySound(136);
NextLevel := TRUE; {happy day, you advanced to the next level}
end;
DrawCopyRects;
end;
end;
end;
RestoreGraphics;
end;
procedure DisposeAll;
var
DisposeObject, CurrObject: ListGameObject;
begin
CurrObject := FirstMovingObject;
while CurrObject <> nil do
begin
DisposeObject := CurrObject^.Next;
dispose(CurrObject);
CurrObject := DisposeObject;
end;
CurrObject := FirstNonMovingObject;
while CurrObject <> nil do
begin
DisposeObject := CurrObject;
CurrObject := CurrObject^.Next;
dispose(DisposeObject);
end;
end; {very simply, get rid of all objects in both lists}
procedure PaddleAndBall;
var
CurrObject: ListGameObject;
CurrentRect: Rect;
begin
CurrObject := FirstObject;
new(FirstObject^.next);
CurrObject := FirstObject^.next;
CurrentRect := CIcons[200]^^.IconPmap.Bounds;
OffsetRect(CurrentRect, 225, 275);
InitOb(CurrObject, PADDLE, PADDLE, 200, CurrentRect, CurrentRect, nil, FirstObject, 0, 0, 0, 0, 0, 0, 0, 0);
new(CurrObject^.next);
CurrentRect := CIcons[300]^^.IconPmap.Bounds;
OffsetRect(CurrentRect, 255, 250);
InitOb(CurrObject^.next, BALL, BALL, 300, CurrentRect, CurrentRect, nil, CurrObject, (random mod 5), 1, 1, 0, 0, 0, 0, 0);
end; {create, and init, both paddle and ball}
procedure UpdateNonMovingGrid;
var
WhereX, WhereY: integer;
begin
for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
begin
CurrentNonMoving := CurrentNonMoving + 1;
with NonMovingList[CurrentNonMoving] do
begin
H := WhereX;
V := WhereY;
end;
end;
end; {does as addtononmovinggrid except doesn't draw}
procedure RemoveFromNonMovingGrid;
var
i, WhereX, WhereY: integer;
begin
for WhereX := (CurrOb^.CurrentPlace.left) div BLOCKSIZE to (CurrOb^.CurrentPlace.right) div BLOCKSIZE do
for WhereY := (CurrOb^.CurrentPlace.top) div BLOCKSIZE to (CurrOb^.CurrentPlace.bottom) div BLOCKSIZE do
for i := 1 to 5 do
if NonMovingGrid[WhereX, WhereY, i] = CurrOb then
NonMovingGrid[WhereX, WhereY, i] := nil;
end; {get rid of it pretty much the same way it was created, from each of its blocks}
procedure AddToNonMovingGrid;
var
a, b, c, d, i, WhereX, WhereY: integer;
begin
for WhereX := ((CurrOb^.CurrentPlace.left) div BLOCKSIZE) to ((CurrOb^.CurrentPlace.right) div BLOCKSIZE) do
for WhereY := ((CurrOb^.CurrentPlace.top) div BLOCKSIZE) to ((CurrOb^.CurrentPlace.bottom) div BLOCKSIZE) do
begin
i := 1;
while NonMovingGrid[WhereX, WhereY, i] <> nil do
i := i + 1;
NonMovingGrid[WhereX, WhereY, i] := CurrOb;
if FALSE then
begin
CurrentNonMoving := CurrentNonMoving + 1;
with NonMovingList[CurrentNonMoving] do
begin
H := WhereX;
V := WhereY;
end;
end; {this USED to be a different way of doing it... i changed it, of course}
Draw(CurrOb);
end;
end; {stick an object in the grid, which includes setting each grid block it's in}
procedure BrickRow;
var
CurrLeft, BrickWidth, BrickHeight, i: integer;
PrevOb, CurrOb: ListGameObject;
begin
BrickWidth := CIcons[500]^^.IconPmap.Bounds.right;
BrickHeight := CIcons[500]^^.IconPmap.Bounds.bottom;
CurrLeft := XStart;
CurrOb := StartOb;
if StartOb <> nil then
PrevOb := StartOb
else
PrevOb := nil;
for i := 1 to NumBricks do
begin
if CurrOb <> nil then
begin
new(CurrOb^.next);
CurrOb := CurrOb^.next;
end
else
new(CurrOb);
CoordAndSize(TempPlace, CurrLeft, YStart, BrickWidth, BrickHeight);
if PrevOb <> nil then
begin
if (abs(random) mod 1000) < score then
InitOb(CurrOb, BRICK, BRICKII, 501, TempPlace, TempPlace, nil, PrevOb, 2, 0, 0, 0, 0, 0, 0, 0)
else
InitOb(CurrOb, BRICK, BRICK, 500, TempPlace, TempPlace, nil, PrevOb, 1, 0, 0, 0, 0, 0, 0, 0);
PrevOb^.next := CurrOb;
end
else
begin
if (abs(random) mod 1000) < score then
InitOb(CurrOb, BRICK, BRICKII, 501, TempPlace, TempPlace, nil, nil, 2, 0, 0, 0, 0, 0, 0, 0)
else
InitOb(CurrOb, BRICK, BRICK, 500, TempPlace, TempPlace, nil, nil, 1, 0, 0, 0, 0, 0, 0, 0);
end;
AddToNonMovingGrid(CurrOb);
CurrLeft := CurrLeft + BrickWidth;
PrevOb := CurrOb;
end;
StartOb := CurrOb;
end; {create a row of bricks, add each to the grid}
{note that you get more grey bricks the higher your score goes}
procedure InitNonMovingGrid;
var
i, j, k: integer;
begin
for i := 1 to 10 do
for j := 1 to 10 do
for k := 1 to 5 do
NonMovingGrid[i, j, k] := nil;
end; {just clear all of the non moving grid}
procedure InitLevel;
var
i: integer;
BlankRect: Rect;
begin
InitNonMovingGrid;
new(FirstMovingObject);
InitOb(FirstMovingObject, 0, 0, 0, BlankRect, BlankRect, nil, nil, 0, 0, 0, 0, 0, 0, 0, 0); {dummy}
PaddleAndBall(FirstMovingObject);
FirstNonMovingObject := nil;
new(FirstNonMovingObject);
InitOb(FirstNonMovingObject, 0, 0, 0, BlankRect, BlankRect, nil, nil, 0, 0, 0, 0, 0, 0, 0, 0); {dummy}
i := CurrentNonMoving;
FlushLevelGraphics(128);
for i := 1 to 7 do
BrickRow(FirstNonMovingObject, 10, 30 + (i * (CIcons[500]^^.IconPmap.Bounds.bottom)), 15);
CurrentNonMoving := i;
end; {make the brick rows, as well as the dummy objects and the paddle and the ball}
procedure InitGame;
var
FirstNonMovingObject, FirstMovingObject: ListGameObject;
begin
{KillEveryBody;}
{see highest note}
if false then
begin
rewrite(TopScore, 'HighScore');
TopScore^ := 10;
put(TopScore);
close(TopScore);
end; {you can uncomment this to set the high score to ten points}
reset(TopScore, 'HighScore');
top := TopScore^;
close(TopScore);
{lives = 3; starting items; etc; you know, fun stuff}
FirstNonMovingObject := nil;
FirstMovingObject := nil;
Lives := 3;
Score := 0;
DeathCountdown := 0;
Missiles := 10;
CoolnessCounter := 0;
DontSuck := FALSE;
GameLoop(FirstNonMovingObject, FirstMovingObject);
end;
end.